package com.googlecode.gamedroid.event.source;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;

import com.googlecode.gamedroid.event.Event;
import com.googlecode.gamedroid.event.EventKey;
import com.googlecode.gamedroid.event.EventReceiver;
import com.googlecode.gamedroid.event.EventType;

public class OrientationSensor implements EventSource, SensorEventListener
{
	// The maximum of these values is the gravitational force (~9.81 m/s²).
	// To simplify the use as a steering wheel, we reduce the amplitude of the X axis
	private static final double[] AMPLITUDE = { 5, 9, 9 }; // TODO add preference ???
	
	private Context mContext;
	private Display mDisplay;
	private Event[] mEvents =
	{
		new Event(EventType.ABS, EventKey.ABS_X),
		new Event(EventType.ABS, EventKey.ABS_Y),
		new Event(EventType.ABS, EventKey.ABS_Z)
	};
	private EventReceiver mReceiver;
	private Sensor mSensor;
	private SensorManager mSensorManager;
	private float[] mValue = new float[3];
	
	public OrientationSensor(Context context)
	{
		mContext = context;
		
		mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
		mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
		
		WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
		mDisplay = windowManager.getDefaultDisplay();
	}
	
	@Override
	public Event[] getEventDefinitions()
	{
		return mEvents;
	}
	
	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy)
	{}
	
	@Override
	public void onSensorChanged(SensorEvent event)
	{
		if(mReceiver == null)
			return;
		
		switch(mDisplay.getRotation())
		{
			case Surface.ROTATION_0:
				mValue[0] = -event.values[0];
				mValue[1] = event.values[1];
				break;
			case Surface.ROTATION_90:
				mValue[0] = event.values[1];
				mValue[1] = event.values[0];
				break;
			case Surface.ROTATION_180:
				mValue[0] = event.values[0];
				mValue[1] = -event.values[1];
				break;
			case Surface.ROTATION_270:
				mValue[0] = -event.values[1];
				mValue[1] = -event.values[0];
				break;
		}
		mValue[2] = event.values[2];
		
		for(byte i = 0; i < 3; i++)
			mEvents[i].setValue(mValue[i] / AMPLITUDE[i]);
		
		mReceiver.emit(mEvents, true);
	}
	
	public void onStart()
	{
		mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME);
	}
	
	public void onStop()
	{
		mSensorManager.unregisterListener(this, mSensor);
	}
	
	@Override
	public void reset()
	{}
	
	@Override
	public void setEvents(short[] events)
	{
		if(events.length != 3)
			throw new IllegalArgumentException();
		
		for(byte i = 0; i < 3; i++)
			mEvents[i].setKey(events[i]);
	}
	
	@Override
	public void setReceiver(EventReceiver receiver)
	{
		mReceiver = receiver;
	}
}
